﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml.Serialization;

namespace TacticalGridWarsMapEdit
{
    /// <summary>
    /// Main form for editing a map
    /// </summary>
    public partial class FormMapEdit : Form
    {        
        public enum TileState { Empty, Cover, Wall, Team1Spawn, Team2Spawn }
        const int tileSize = 30;
        private FormProperties formProperties = new FormProperties();
        private FormHelper formHelper = new FormHelper();
        private FormNameMap formSaveMap = new FormNameMap();

        private Tile[,] level;

        private int columns = 0;
        private int rows = 0;
        public int teamMembers = 0;
        public List<Spawn> Spawns { get; set; }

        public FormMapEdit()
        {
            InitializeComponent();
            Spawns = new List<Spawn>();
        }

        private void FormMapEdit_Load(object sender, EventArgs e)
        {
            formProperties.ShowDialog();
            columns = formProperties.Columns;
            rows = formProperties.Rows;

            if (columns > 4)
            {
                this.Width = columns * tileSize + 17;
            }
            if (rows > 1)
            {

                this.Height = rows * tileSize + 39; 
            }
            level = new Tile[rows, columns];
        }

        private void FormMapEdit_Paint(object sender, PaintEventArgs e)
        {
            Graphics g = this.CreateGraphics();
            Brush brushWall = new SolidBrush(Color.Blue);
            Brush brushCover = new SolidBrush(Color.Cyan);
            Brush brushSpawn1 = new SolidBrush(Color.Green);
            Brush brushSpawn2 = new SolidBrush(Color.Purple);
            Pen pen = new Pen(new SolidBrush(Color.Black));

            for (int i = 0; i < rows; i++)
            {
                for (int j = 0; j < columns; j++)
                {
                    if (level[i,j].State == TileState.Cover)
                    {
                        g.FillRectangle(brushCover, j * tileSize, i * tileSize, tileSize, tileSize);
                    }
                    else if (level[i, j].State == TileState.Wall)
                    {
                        g.FillRectangle(brushWall, j * tileSize, i * tileSize, tileSize, tileSize);
                    }
                    else if (level[i, j].State == TileState.Team1Spawn)
                    {
                        g.FillRectangle(brushSpawn1, j * tileSize, i * tileSize, tileSize, tileSize);
                    }
                    else if (level[i, j].State == TileState.Team2Spawn)
                    {
                        g.FillRectangle(brushSpawn2, j * tileSize, i * tileSize, tileSize, tileSize);
                    }
                    g.DrawRectangle(pen, j * tileSize, i * tileSize, tileSize, tileSize);
                }
            }
        }

        private void FormMapEdit_MouseDown(object sender, MouseEventArgs e)
        {
            //level[(int)(e.Y / tileSize + 0.5), (int)(e.X / tileSize + 0.5)].Wall = false;
            //level[(int)(e.Y / tileSize + 0.5), (int)(e.X / tileSize + 0.5)].Cover = false;
            //level[(int)(e.Y / tileSize + 0.5), (int)(e.X / tileSize + 0.5)].SpawnTeam1 = false;
            //level[(int)(e.Y / tileSize + 0.5), (int)(e.X / tileSize + 0.5)].SpawnTeam2 = false;
            if (e.Button == MouseButtons.Left)
            {
                if (Control.ModifierKeys == Keys.Shift)
                {
                    level[(int)(e.Y / tileSize + 0.5), (int)(e.X / tileSize + 0.5)].State = TileState.Team1Spawn;
                }
                else if (Control.ModifierKeys == Keys.Control)
                {
                    level[(int)(e.Y / tileSize + 0.5), (int)(e.X / tileSize + 0.5)].State = TileState.Empty;
                }
                else
                {
                    level[(int)(e.Y / tileSize + 0.5), (int)(e.X / tileSize + 0.5)].State = TileState.Wall;
                }
            }
            else if (e.Button == MouseButtons.Right)
            {
                if (Control.ModifierKeys == Keys.Shift)
                {
                    level[(int)(e.Y / tileSize + 0.5), (int)(e.X / tileSize + 0.5)].State = TileState.Team2Spawn;
                }
                else
                {
                    level[(int)(e.Y / tileSize + 0.5), (int)(e.X / tileSize + 0.5)].State = TileState.Cover;
                }
            }
            this.Invalidate();
        }

        private bool SpawnsOK()
        {
            Spawns.Clear();
            int team1Spawns = 0;
            int team2Spawns = 0;
            for (int i = 0; i < rows; i++)
            {
                for (int j = 0; j < columns; j++)
                {
                    if (level[i, j].State == TileState.Team1Spawn)
                    {
                        Spawns.Add(new Spawn(1, i, j));
                        team1Spawns++;
                    }
                    else if (level[i, j].State == TileState.Team2Spawn)
                    {
                        Spawns.Add(new Spawn(2, i, j));
                        team2Spawns++;
                    }
                }
            }
            if (team1Spawns == team2Spawns)
            {
                teamMembers = team1Spawns;
                return true;
            }
            else
            {
                return false;
            }
        }

        private void SaveMap(string levelName)
        {
		    SaveLevel saveLevel = new SaveLevel();
            XmlSerializer serializer = new XmlSerializer(typeof(SaveLevel));

            saveLevel.Convert(level, teamMembers, Spawns);
            TextWriter writer = new StreamWriter(levelName + ".xml");

            serializer.Serialize(writer, saveLevel);
            writer.Close();
        }

        private void LoadMap(string levelName)
        {
            SaveLevel saveLevel = new SaveLevel();
            XmlSerializer serializer = new XmlSerializer(typeof(SaveLevel));

            StreamReader file = new StreamReader(levelName + ".xml");
            saveLevel = (SaveLevel)serializer.Deserialize(file);
            file.Close();
            saveLevel.Load(ref level, ref teamMembers, Spawns);
            rows = level.GetLength(0);
            columns = level.GetLength(1);
            this.Width = columns * tileSize + 17;
            this.Height = rows * tileSize + 39; 
        }

        private void FormMapEdit_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.S && Control.ModifierKeys == Keys.Control)
            {
                if (SpawnsOK())
                {
                    formSaveMap.Text = "Savename";
                    formSaveMap.ShowDialog();
                    if (formSaveMap.DialogResult == DialogResult.OK)
                    {
                        SaveMap(formSaveMap.LevelName);
                    }
                }
                else
                {
                    MessageBox.Show("Invalid spawn placement\n" + "Teams must have same number of spawnpoints..", "Invalid Spawns", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
	        }
            else if (e.KeyCode == Keys.L && Control.ModifierKeys == Keys.Control)
            {
                formSaveMap.Text = "Load file";
                formSaveMap.ShowDialog();
                if (formSaveMap.DialogResult == DialogResult.OK)
                {
                    LoadMap(formSaveMap.LevelName);
                }
            }
            else if (e.KeyCode == Keys.F1)
            {                
                formHelper.Show();
            }
        }

        public struct Tile
        {
            public TileState State { get; set; }

        }

        public class Spawn
        {
            public int Team { get; set; }
            public int XPos { get; set; }
            public int YPos { get; set; }
            public Spawn()
            {
                Team = XPos = YPos = 0;
            }
            public Spawn(int team, int xPos, int yPos)
            {
                Team = team;
                XPos = xPos;
                YPos = yPos;
            }
        }

        [Serializable()]
        [XmlType(AnonymousType = true)]
        [XmlRoot("SaveLevel")]
        public class SaveLevel
        {
            public int Rows;
            public int Columns;
            public int TeamMembers;
            public TileState State;
            public List<Tile> Level = new List<Tile>();
            public List<Spawn> Spawns = new List<Spawn>();

            public void Convert(Tile[,] level, int teamMembers, List<Spawn> spawns)
            {
                Level.Clear();
                Spawns.Clear();
                Spawns = spawns;
                Rows = level.GetLength(0);
                Columns = level.GetLength(1);
                TeamMembers = teamMembers;
                for (int i = 0; i < Rows; i++)
                {
                    for (int j = 0; j < Columns; j++)
                    {
                        Level.Add(level[i, j]);
                    }
                }
            }

            public void Load(ref Tile[,] level, ref int teamMembers, List<Spawn> spawns)
            {
                spawns.Clear();
                spawns.AddRange(Spawns);
                level = new Tile[Rows, Columns];
                teamMembers = TeamMembers;
                for (int i = 0; i < Rows; i++)
                {
                    for (int j = 0; j < Columns; j++)
                    {
                        level[i, j] = Level[i * Columns + j];
                    }
                }
            }
        }
    }
}
